SpringMVC FreeMarker SiteMesh3整合

版本信息

系统信息

  • Spring(4.3.18.RELEASE) + Spring MVC(4.3.18.RELEASE) + Mybatis(3.4.6)
  • FreeMarker(2.3.28)
  • SiteMesh(3.0.1)

SpringMVC集成FreeMarker

1.首先导入包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>

<!--freemarker需要spring-context-support的支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>

<dependency>
<groupId>org.sitemesh</groupId>
<artifactId>sitemesh</artifactId>
<version>3.0.1</version>
</dependency>

2.SpringMVC 集成 FreeMarker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<!--spring-mvc.xml 设置视图解析器-->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="false"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
<property name="viewClass"
value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<property name="exposeSpringMacroHelpers" value="false"/>
<property name="exposeSessionAttributes" value="true"/>
<property name="exposeRequestAttributes" value="true"/>
<property name="allowSessionOverride" value="true"/>
<property name="allowRequestOverride" value="true"/>
<property name="order" value="0"/>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--spring-freemarker.xml 配置freemarker信息-->
<bean id="freemarkerConfiguration" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:/conf/freemarker.properties"/>
</bean>

<bean id="freeMarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/pages/"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="freemarkerVariables">
<map>
<entry key="ctx" value="${smart.machinery.url}"/>
<entry key="xml_escape" value-ref="fmXmlEscape"/>
</map>
</property>
<property name="freemarkerSettings" ref="freemarkerConfiguration"/>
</bean>

<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
1
2
3
4
5
6
7
8
9
10
11
# freemarker.properties 配置文件

tag_syntax=auto_detect
template_update_delay=2
default_encoding=UTF-8
output_encoding=UTF-8
locale=zh_CN
date_format=yyyy-MM-dd
time_format=HH:mm:ss
datetime_format=yyyy-MM-dd HH:mm:ss
number_format=#
1
2
3
4
5
6
<!--application.xml spring配置文件-->
<context:property-placeholder location="classpath:/conf/*.properties"/>
<beans>
<import resource="application-mvc.xml"/>
<import resource="application-freemarker.xml"/>
</beans>

3.集成sitemesh3

sitemesh3本身是独立于Freemarker和Spring的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--在WEB-INF目录下增加sitemesh3.xml文件,这是sitemesh的默认配置路径,如果修改需要在web.xml中做修改-->
<sitemesh>
<!-- 参阅配置文档:https://www.cnblogs.com/lzrabbit/p/5176992.html -->
<mime-type>text/html</mime-type>
<!--这个路径是说装饰模板的位置,不要配置全路径,因为在freemarker已经设置了模板所在路径,不能写成全路径,否则会报错导致视图无法被加载报空指针异常-->
<mapping path="/*" decorator="/decorators/decorator.ftl"/>

<mapping path="/static/*" exclue="true"/>
<mapping path="/index.html" exclue="true"/>

<content-processor>
<!--自定义的标签-->
<tag-rule-bundle class="com.microthings.smart.machinery.sitemesh.CustomTagRuleBundle"/>
</content-processor>
</sitemesh>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--web.xml配置-->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--自定义的freemarker过滤器,如果不实现的话会导致freemarker的模板标签不可用-->
<filter>
<filter-name>freemarkerFilter</filter-name>
<filter-class>com.microthings.smart.machinery.filter.CustomFreemarkerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>freemarkerFilter</filter-name>
<url-pattern>*.ftl</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

// FreeMarker自定义的过滤器
public class CustomFreemarkerFilter implements Filter {
private Locale l;

private ApplicationContext ctx;

@Override
public void init(FilterConfig filterConfig) throws ServletException {
String locale = filterConfig.getInitParameter("locale");
if (StringUtils.hasText(locale)) {
l = new Locale(locale);
} else {
l = Locale.getDefault();
}
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (ctx == null) {
ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getSession().getServletContext());
if (ctx == null) {
throw new ExceptionInInitializerError("Spring context is not loaded");
}
}
try {
FreeMarkerViewResolver viewResolver = ctx.getBean(FreeMarkerViewResolver.class);
FreeMarkerConfigurer freeMarkerConfigurer = ctx.getBean(FreeMarkerConfigurer.class);
Configuration configuration = freeMarkerConfigurer.getConfiguration();
String uri = req.getRequestURI();
<!--此处是为了去除该应用的应用名,如果是/路径的话直接写 1 即可-->
String tm = configuration.getSharedVariable("ctx").toString();
uri = uri.substring(uri.indexOf(tm) + tm.length() + 1, uri.lastIndexOf(".ftl"));

View view = viewResolver.resolveViewName(uri, l);
view.render(null, req, res);
} catch (Exception e) {
throw new ServletException(e);
}
}

@Override
public void destroy() {

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

// 自定义的sitemesh标签

public class CustomTagRuleBundle implements TagRuleBundle {
@Override
public void install(State state, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
state.addRule("pc", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("pc"), false));
state.addRule("js", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("js"), false));
state.addRule("css", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("css"), false));

}

@Override
public void cleanUp(State state, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
if (!contentProperty.getChild("pc").hasValue()) {
contentProperty.getChild("pc").setValue(contentProperty.getValue());
}
if (!contentProperty.getChild("js").hasValue()) {
contentProperty.getChild("js").setValue(contentProperty.getValue());
}
if (!contentProperty.getChild("css").hasValue()) {
contentProperty.getChild("css").setValue(contentProperty.getValue());
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!--位于/WEB-INF/pages/decorators/decorator.ftl 模板-->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta charset="utf-8"/>

<title>
<sitemesh:write property='title'/>
</title>
<#-- HEAD CSS BEGINS-->
<sitemesh:write property='css'/>
<#-- HEAD CSS ENDS-->

<#-- HEAD JS BEGINS-->
<sitemesh:write property='js'/>
<#-- HEAD JS ENDS-->

</head>
<body>
<#-- BODY BEGINS-->
<sitemesh:write property='body'/>
<#-- BODY ENDS-->
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
<!--test.ftl测试界面-->
<title>
测试
</title>

<body>
<p>测试界面 fasfdasfasfdsaf</p>
<p>${t}</p>
<p>${b}</p>
</body>
<pc>
<p>test Page Content</p>
</pc>
1
2
3
4
5
6
7
8
9
10
11
12
// 测试Controller
@Controller
@RequestMapping("/test")
public class TestController {

@GetMapping
public String test(ModelMap modelMap) {
modelMap.put("t", "测试");
modelMap.put("b", "测试页面");
return "/test";
}
}

参考文章

  1. SiteMesh3整合SpringMVC+FreeMarker
  2. 解决sitemesh3装饰页面不能使用freemarker标签问题

总结

  1. 使用spring-boot装饰页面的时候感觉挺简单的,怎么感觉到了springmvc这个问题挺多的,可能使用的模板引擎不太一样;
  2. 再一个就是注意freemarker的模板标签不能使用的问题。